using GraphProcessor;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Logic;
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay.Editors
{
    public partial class LevelServiceBlackboard
    {
        public List<string> allExectuionGroupID => this.editorCache?.allExectuionGroupID;

        private Dictionary<string, List<(EditorLevelServiceExecutionConfig, LevelServiceExecutionNode)>> exectuionGroupCache =
            new Dictionary<string, List<(EditorLevelServiceExecutionConfig, LevelServiceExecutionNode)>>();
        private LevelServiceExecutionNode syncTempNode;

        public void AddExecutionGroup(string groupID, EditorLevelServiceExecutionConfig config, LevelServiceExecutionNode node)
        {
            if (string.IsNullOrEmpty(groupID))
            {
                return;
            }
            if (!this.allExectuionGroupID.Contains(groupID))
            {
                this.allExectuionGroupID.Add(groupID);
            }
            if (this.syncTempNode == null || this.syncTempNode == node)
            {
                if (!this.exectuionGroupCache.TryGetValue(groupID, out var rList))
                {
                    rList = new List<(EditorLevelServiceExecutionConfig, LevelServiceExecutionNode)>();
                    this.exectuionGroupCache.Add(groupID, rList);
                }
                var rOldIndex = rList.FindIndex(x => x.Item1.executionType == config.executionType);
                if (rOldIndex != -1)
                {
                    rList[rOldIndex] = (config, node);
                }
                else
                {
                    rList.Add((config, node));
                }
                this.exectuionGroupCache[groupID] = rList;
            }
        }

        public void SyncExecutionOnNode(LevelServiceExecutionNode tempNode)
        {
            this.Clear();
            this.syncTempNode = tempNode;
            // 执行一遍
            var rSortList = tempNode.Graph.nodes.OrderBy(n => n.computeOrder).ToList();
            for (int k = 0; k < rSortList.Count; k++)
            {
                var rNode = rSortList[k];
                rNode.OnProcess();
            }
            // 在这里就可以只同步特定节点了
            this.SyncExecutionOnGraph();

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            this.Clear();
        }

        public void SyncExecutionOnGraph()
        {
            List<BaseGraph> rAllGraph = this.GetAllGraph();

            foreach (var rPair in this.exectuionGroupCache)
            {
                for (int i = 0; i < rPair.Value.Count; i++)
                {
                    var rItem = rPair.Value[i];
                    this.SyncExecution(rPair.Key, rItem.Item1, rItem.Item2, rAllGraph);
                }
            }

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            this.Clear();
            LogGame.Log($"关卡服务预设同步完成");
        }

        private void SyncExecution(string key, EditorLevelServiceExecutionConfig config, LevelServiceExecutionNode tempNode, List<BaseGraph> allGraph)
        {
            for (int i = 0; i < allGraph.Count; i++)
            {
                var graph = allGraph[i];
                var rList = graph.nodes;
                for (int j = 0; j < rList.Count; j++)
                {
                    if (rList[j] is LevelServiceExecutionNode rExeNode && rExeNode != tempNode && rExeNode.executionGroupID == key)
                    {
                        rExeNode.Sync(config, tempNode);
                        EditorUtility.SetDirty(graph);
                    }
                }
            }
        }

        public void FindAllServiceByExecution(LevelServiceExecutionNode tempNode)
        {
            var rTempGraph = tempNode.Graph;
            var rPath = AssetDatabase.GetAssetPath(rTempGraph);
            rPath = Path.GetDirectoryName(rPath);
            var rAllGraph = this.GetAllGraph(rPath);
            var rObjList = new List<UnityEngine.Object>();
            for (int i = 0; i < rAllGraph.Count; i++)
            {
                var rGraph = rAllGraph[i];
                var bHasTargetNode = rGraph.nodes.Exists((x) =>
                {
                    if (x is LevelServiceExecutionNode rExNode)
                    {
                        return rExNode.serviceType == tempNode.serviceType;
                    }
                    return false;
                });
                if (bHasTargetNode)
                {
                    rObjList.Add(rGraph);
                    LogGame.Log(AssetDatabase.GetAssetPath(rGraph));
                }
            }
            Selection.objects = rObjList.ToArray();
        }
    }
}